/*
 * @Descripttion: OSS文件上传相关工具函数
 * @Author: Cascade
 * @Date: 2025-06-02
 * @LastEditTime: 2025-07-07 11:00:23
 * @LastEditors: sueRimn
 */

import { getOssPolicy } from '@/api/apiMap/oss'

// OSS策略缓存对象
let ossPolicy = null;
let ossPolicyExpiration = null;

/**
 * 获取有效的OSS策略
 * @returns {Promise<Object>} OSS策略对象
 */
export async function getValidOssPolicy() {
  // 如果缓存中存在未过期的策略则直接使用
  const now = Date.now();
  if (ossPolicy && ossPolicyExpiration && now < ossPolicyExpiration) {
    console.log('[OSS] 使用缓存的OSS策略，还有', Math.floor((ossPolicyExpiration - now) / 1000), '秒过期');
    return ossPolicy;
  }
  
  // 如果没有缓存的策略或者已过期，重新获取
  console.log('[OSS] 获取新的OSS策略');
  const res = await getOssPolicy();
  if (res.code !== 200) {
    throw new Error(res.message || '获取上传凭证失败');
  }
  
  // 缓存策略
  ossPolicy = res.data;
  
  // 设置过期时间，比策略过期时间提前60秒过期
  if (ossPolicy.expiration) {
    try {
      ossPolicyExpiration = new Date(ossPolicy.expiration).getTime() - 60000; // 比实际过期时间提前60秒
    } catch (e) {
      // 如果解析expiration出错，设置10分钟过期
      ossPolicyExpiration = now + 600000; // 10分钟
    }
  } else {
    // 如果没有过期时间，默认10分钟
    ossPolicyExpiration = now + 600000;
  }
  
  console.log('[OSS] 策略过期时间:', new Date(ossPolicyExpiration).toLocaleString());
  return ossPolicy;
}

/**
 * 生成唯一文件名
 * @param {File|Object} file 文件对象
 * @param {String} bizDir 业务目录
 * @returns {String} 生成的文件名
 */
export function generateFileName(file, bizDir = 'common') {
  const date = new Date();
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  
  // 从原始文件名中获取扩展名
  const fileName = file.name || '';
  const extIndex = fileName.lastIndexOf('.');
  const ext = extIndex > -1 ? fileName.slice(extIndex) : '';
  
  // 生成随机字符串
  const random = Math.random().toString(36).substring(2, 10);
  const timestamp = Date.now();
  
  // 格式：bizDir/year/month/day/timestamp_random.ext
  return `${bizDir}/${year}${month}${day}/${timestamp}_${random}${ext}`;
}

/**
 * 上传文件到OSS
 * @param {File|Object} file 文件对象（微信环境下为包含path或tempFilePath的对象）
 * @param {Function} onProgress 上传进度回调
 * @param {String} bizDir 业务目录
 * @returns {Promise} 上传结果
 */
export async function uploadFileToOss(file, onProgress, bizDir = 'common') {
  try {
    // 使用缓存的OSS策略获取方法
    const policy = await getValidOssPolicy();
    console.log('[OSS] Using policy with host:', policy.host);
    
    // 生成唯一文件名
    // 使用服务器返回的dir前缀（如果有）
    const dirPrefix = policy.dir ? policy.dir + '/' : '';
    const fileName = dirPrefix + generateFileName(file, bizDir);
    
    // 创建FormData对象用于上传
    const formData = {
      'key': fileName,
      'success_action_status': '200'
    };
    
    // 添加OSS需要的字段
    // 处理不同的accessKeyId字段名称
    if (policy.accessid) {
      formData.OSSAccessKeyId = policy.accessid;
    } else if (policy.accessKeyId) {
      formData.OSSAccessKeyId = policy.accessKeyId;
    } else if (policy.OSSAccessKeyId) {
      formData.OSSAccessKeyId = policy.OSSAccessKeyId;
    } else {
      throw new Error('上传凭证无效: 缺少AccessKeyId');
    }
    
    // 添加security token（如果存在）
    if (policy.securityToken) {
      formData['x-oss-security-token'] = policy.securityToken;
    }
    
    // 添加policy和signature
    if (!policy.policy) {
      throw new Error('上传凭证无效: 缺少policy');
    }
    
    formData.policy = policy.policy;
    
    // 添加签名
    let signature = policy.signature;
    let isOss4 = false;
    
    // 检查是否是OSS 4.0签名版本
    if (policy['x-oss-signature-version'] === 'OSS4-HMAC-SHA256' || policy['signature_version'] === 'OSS4-HMAC-SHA256') {
      isOss4 = true;
      console.log('[OSS] 使用OSS 4.0签名版本');
      
      // 处理签名字段名称可能的不同
      if (policy['x-oss-signature']) {
        signature = policy['x-oss-signature'];
      } else if (policy['signature']) {
        signature = policy['signature'];
      }
      
      // 添加OSS 4.0版本特有字段
      formData['x-oss-signature-version'] = policy['x-oss-signature-version'] || policy['signature_version'] || 'OSS4-HMAC-SHA256';
      
      // 确保添加 x-oss-date 字段
      if (policy['x-oss-date']) {
        formData['x-oss-date'] = policy['x-oss-date'];
      } else if (policy['date']) {
        formData['x-oss-date'] = policy['date'];
      } else {
        // 如果服务器没有提供，使用当前时间
        formData['x-oss-date'] = new Date().toISOString().replace(/\.\d+Z$/, 'Z');
      }
      
      // 处理 x-oss-credential 字段，这是必需的
      if (policy['x-oss-credential']) {
        formData['x-oss-credential'] = policy['x-oss-credential'];
      } else if (policy['credential']) {
        formData['x-oss-credential'] = policy['credential'];
      } else if (policy['accessid']) {
        // 如果服务器没有提供完整的credential，尝试使用accessid代替
        formData['x-oss-credential'] = policy['accessid'];
        console.warn('[OSS] 使用accessid替代x-oss-credential，这可能不符合OSS规范');
      } else if (policy['accessKeyId']) {
        formData['x-oss-credential'] = policy['accessKeyId'];
        console.warn('[OSS] 使用accessKeyId替代x-oss-credential，这可能不符合OSS规范');
      } else {
        console.error('[OSS] 缺少 x-oss-credential 字段', policy);
        throw new Error('上传凭证无效: 缺少 x-oss-credential');
      }
      
      // 添加其他字段（如果有）
      if (policy['x-oss-additional-headers']) {
        formData['x-oss-additional-headers'] = policy['x-oss-additional-headers'];
      } else if (policy['additional-headers']) {
        formData['x-oss-additional-headers'] = policy['additional-headers'];
      }
    }
    
    // 添加安全令牌（如果有）
    if (policy['x-oss-security-token']) {
      formData['x-oss-security-token'] = policy['x-oss-security-token'];
    }
    
    // 确保签名存在
    if (!signature) {
      console.error('策略中缺少签名字段', policy);
      throw new Error('上传凭证无效: 缺少签名字段');
    }
    
    // 根据签名版本使用不同的字段名
    if (isOss4) {
      formData['x-oss-signature'] = signature;
    } else {
      formData.signature = signature;
    }
    
    // 确保host字段存在
    if (!policy.host) {
      throw new Error('上传凭证无效: 缺少host字段');
    }
    
    // 使用uni.uploadFile上传
    return new Promise((resolve, reject) => {
      // 确保有效的文件路径
      const filePath = file.path || file.tempFilePath;
      if (!filePath) {
        return reject(new Error('无效的文件路径'));
      }
      
      console.log('[OSS] 准备上传文件:', {
        host: policy.host,
        filePath,
        formDataKeys: Object.keys(formData)
      });
      
      const uploadTask = uni.uploadFile({
        url: policy.host,
        filePath: filePath,
        name: 'file',
        formData: formData,
        success: (res) => {
          console.log("OSS上传响应:", res);
          // 微信小程序中响应的statusCode是字符串类型
          const statusCode = parseInt(res.statusCode) || res.statusCode;
          if (statusCode >= 200 && statusCode < 300) {
            // 构建完整的文件URL
            let fileUrl;
            
            // 如果服务器返回了CDN域名，优先使用
            if (policy.cdn_domain) {
              const cdnHost = policy.cdn_domain.startsWith('http') ? policy.cdn_domain : `https://${policy.cdn_domain}`;
              fileUrl = cdnHost.endsWith('/') ? `${cdnHost}${fileName}` : `${cdnHost}/${fileName}`;
            } 
            // 如果服务器返回了文件URL前缀，次优先使用
            else if (policy.fileUrlPrefix) {
              fileUrl = `${policy.fileUrlPrefix}${fileName}`;
            }
            // 否则使用host构建
            else {
              if (policy.host.endsWith('/')) {
                fileUrl = `${policy.host}${fileName}`;
              } else {
                fileUrl = `${policy.host}/${fileName}`;
              }
            }
            
            resolve({
              name: file.name || fileName.split('/').pop(),
              fileName: fileName,
              fileUrl: fileUrl,
              filePath: fileName,
              success: true
            });
          } else {
            const errMsg = res.data ? JSON.stringify(res.data) : `上传失败: 状态码 ${res.statusCode}`;
            console.error('上传错误:', errMsg);
            reject(new Error(errMsg));
          }
        },
        fail: (err) => {
          console.error('上传失败:', err);
          reject(new Error('上传失败: ' + (err.errMsg || '网络错误')));
        }
      });
      
      // 监听上传进度
      if (onProgress && uploadTask.onProgressUpdate) {
        uploadTask.onProgressUpdate((res) => {
          onProgress(res.progress);
        });
      }
    });
  } catch (error) {
    console.error('上传到OSS失败:', error);
    uni.showToast({
      title: error.message || '上传失败',
      icon: 'none'
    });
    throw error;
  }
}

/**
 * 从微信选择图片并上传到OSS
 * @param {Object} options 选择图片的配置项
 * @param {String} bizDir 业务目录
 * @param {Function} onProgress 上传进度回调
 * @returns {Promise} 上传结果
 */
export function chooseImageAndUpload(options = {}, bizDir = 'avatar', onProgress) {
  return new Promise((resolve, reject) => {
    uni.chooseImage({
      count: options.count || 1,
      sizeType: options.sizeType || ['original', 'compressed'],
      sourceType: options.sourceType || ['album', 'camera'],
      success: async (res) => {
        try {
          const tempFiles = res.tempFiles;
          const tempFilePaths = res.tempFilePaths;
          
          // 单张图片上传
          if (tempFiles.length === 1) {
            const result = await uploadFileToOss(
              { 
                path: tempFilePaths[0],
                name: tempFiles[0].name || tempFilePaths[0].split('/').pop(),
                size: tempFiles[0].size
              }, 
              onProgress, 
              bizDir
            );
            resolve(result);
          } 
          // 多张图片上传
          else {
            const uploadPromises = tempFiles.map((file, index) => {
              return uploadFileToOss(
                { 
                  path: tempFilePaths[index],
                  name: file.name || tempFilePaths[index].split('/').pop(),
                  size: file.size
                }, 
                null, // 多张图片上传不监控单个进度
                bizDir
              );
            });
            
            const results = await Promise.all(uploadPromises);
            resolve(results);
          }
        } catch (error) {
          reject(error);
        }
      },
      fail: (err) => {
        if (err.errMsg.indexOf('cancel') > -1) {
          // 用户取消选择，不显示错误
          reject(new Error('用户取消选择'));
        } else {
          uni.showToast({
            title: '选择图片失败',
            icon: 'none'
          });
          reject(new Error('选择图片失败: ' + err.errMsg));
        }
      }
    });
  });
}

/**
 * 验证文件大小和类型
 * @param {Object} file 文件对象
 * @param {Number} maxSize 最大文件大小(MB)
 * @param {Array} acceptTypes 接受的文件类型数组(可选)
 * @returns {Boolean} 验证是否通过
 */
export function validateFile(file, maxSize, acceptTypes) {
  // 验证文件大小
  const maxSizeBytes = maxSize * 1024 * 1024;
  if (file.size > maxSizeBytes) {
    uni.showToast({
      title: `文件大小不能超过${maxSize}MB`,
      icon: 'none'
    });
    return false;
  }
  
  // 如果指定了文件类型，验证文件类型
  if (acceptTypes && acceptTypes.length > 0) {
    const fileName = file.name || file.path || '';
    const fileNameParts = fileName.split('.');
    const fileExt = fileNameParts.length > 1 ? fileNameParts.pop().toLowerCase() : '';
    
    const isValidType = acceptTypes.some(type => {
      // 清理类型字符串
      const cleanType = type.trim().replace('*', '');
      
      // 处理类似 '.jpg,.png' 的格式
      if (cleanType.startsWith('.')) {
        return fileExt === cleanType.slice(1).toLowerCase();
      }
      // 处理文件扩展名
      else if (cleanType) {
        return fileExt === cleanType.toLowerCase();
      }
      return false;
    });
    
    if (!isValidType) {
      uni.showToast({
        title: `只能上传 ${acceptTypes.join(', ')} 类型的文件`,
        icon: 'none'
      });
      return false;
    }
  }
  
  return true;
}
